/*****************************************************
*   Class CHttpReq
*   Used for a normal GET http request
*   Capsulate into a High level object
*
*   Example:
*   CHttpReq myReq("http://api.t.sina.com.cn/statuses/followers.xml?user_id=", false);
*   if(myReq.startReq()) cout<<myReq.getResult()<<endl;
*
*   By GuiQing, (c)2010     Specialisation Level : Generic HTTP Req
******************************************************/



#ifndef CHTTPREQ_H_INCLUDED
#define CHTTPREQ_H_INCLUDED

#include "GlobalConfig.h"
#include <wx/url.h>
#include <wx/msgdlg.h>
#include <map>

class wxInputStream;
class wxCriticalSection;

class CHttpReq{

    friend class CHttpReqLimited;
    friend class CHttpReqBLOB;
    friend class CLogin;
    #ifdef UNIT_TEST
    friend class UnitTest_OAuth;
    #endif

    class OauthData
    {
        public:
        OauthData()
        :mHttpHeader("")
        ,mHttpMethod(HTTP_METHOD_GET)
        {

        }

        wxString mHttpHeader;
        wxString mHttpMethod;
    };

    private:
        //socket event may be sent out even sokect obj is destroyed.
        wxHTTP httpReq;     //Do not create socket obj in the stack
        const int retrySec;     //retry interval in seconds
        const int timeOutSec;
        wxString destHost;
        wxString destPath;
        wxString mOauthBaseURL;
        std::map<wxString, wxString> mQueryParamsTable;
        wxInputStream *httpStream;
        bool auth;
        wxCriticalSection* mpHttpReqCS;
        OauthData mOauthData;

        inline void splitURL(const wxString& urlStr_IN);
        bool retryConn(const wxString& destHost);
        void extractBaseURLAndQueryParsms(const wxString& fullURL);

    protected:
        wxString reqResult;
        bool startReq(const wxString& urlStr_IN ,const wxString& postBuf = "");
        void setOauthHeader(const wxString& _headerStr, const wxString& _httpType);
        void generateOauthAccessHeader(const wxString& fullURL , const wxString& _httpType);

        // Prohibition of copy to avoid ptr unexpected behavior
        //CHttpReq(const CHttpReq& obj);
        //constructor : accidently type convention will perform this rate limited version

    public:

        int retryCount;
        int httpErrCode;
        wxString errorInfo;

        //RFC2616
        enum ErrorCodeType{
            OK = 200,                                //OK
            NOT_MODIFIED = 304,              //Not Modified
            BAD_REQUEST = 400,               //Bad Request
            NOT_AUTHORIZED = 401,         //Not Authorized
            NOT_START = 402,                  //Not Start mblog
            FORBIDDEN = 403,                  //Forbidden
            NOT_FOUND = 404,                 //Not Found
            INTERNAL_ERROR = 500,         //Internal Server Error
            BAD_GATEWAY = 502,            //Bad Gateway
            SERVICE_UNAVAILABLE = 503 //Service Unavailable
        };

        CHttpReq (const bool auth_IN=true , const int retrySec_IN=HTTP_RETRY_WAIT_SEC, const int timeOutSec_IN=HTTP_TIME_OUT_SEC);
        virtual ~CHttpReq();

        const wxString& getResult() const {return reqResult;}

        //static void set_usr_pwd(const wxString& usr_IN, const wxString& pwd_IN) throw();
};


inline void CHttpReq::splitURL(const wxString& urlStr_IN)
{
    if(wxNOT_FOUND!=urlStr_IN.Find("http://"))
    {
        destHost = urlStr_IN.Mid(7).BeforeFirst('/');
        destPath = wxT("/")+urlStr_IN.Mid(7).AfterFirst('/');
    }
    else
    {
        assert(false);  //OAuth signing need a URL including http://
    }
}


inline void CHttpReq::setOauthHeader(const wxString& _headerStr, const wxString& _httpType)
{
    mOauthData.mHttpHeader = _headerStr;
    mOauthData.mHttpMethod =_httpType;
}

#endif // CHTTPREQ_H_INCLUDED
